package syncx

import (
	"sync"
	"testing"
	"time"
)

// 测试对比IDLocker与直接使用map[string]*sync.Mutex的性能差异

// 简单的map实现，用于对比
type SimpleIDLocker struct {
	mu   sync.Mutex
	data map[string]*sync.Mutex
}

func NewSimpleIDLocker() *SimpleIDLocker {
	return &SimpleIDLocker{
		data: make(map[string]*sync.Mutex),
	}
}

func (s *SimpleIDLocker) Lock(id string) {
	s.mu.Lock()
	mutex, ok := s.data[id]
	if !ok {
		mutex = &sync.Mutex{}
		s.data[id] = mutex
	}
	s.mu.Unlock()

	mutex.Lock()
}

func (s *SimpleIDLocker) Unlock(id string) {
	s.mu.Lock()
	mutex, ok := s.data[id]
	s.mu.Unlock()

	if ok {
		mutex.Unlock()
	}
}

// 性能对比测试
func BenchmarkCompareBasicOperations(b *testing.B) {
	// 1. 使用我们的IDLocker
	b.Run("IDLocker", func(b *testing.B) {
		locker := NewIDLocker()
		defer locker.Close()

		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			id := "test-" + string(rune(i%100+'a'))
			locker.Lock(id)
			locker.Unlock(id)
		}
	})

	// 2. 使用简单的map实现
	b.Run("SimpleMapLocker", func(b *testing.B) {
		locker := NewSimpleIDLocker()

		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			id := "test-" + string(rune(i%100+'a'))
			locker.Lock(id)
			locker.Unlock(id)
		}
	})
}

// 并发性能对比测试 - 不同ID
func BenchmarkCompareConcurrentDifferentIDs(b *testing.B) {
	// 1. 使用我们的IDLocker
	b.Run("IDLocker", func(b *testing.B) {
		locker := NewIDLocker()
		defer locker.Close()

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			// 每个goroutine使用唯一ID
			localID := "test-" + time.Now().String()
			counter := 0

			for pb.Next() {
				// 随机更换ID，模拟真实场景
				if counter%10 == 0 {
					localID = "test-" + string(rune(counter%26+'a'))
				}
				counter++

				locker.Lock(localID)
				locker.Unlock(localID)
			}
		})
	})

	// 2. 使用简单的map实现
	b.Run("SimpleMapLocker", func(b *testing.B) {
		locker := NewSimpleIDLocker()

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			// 每个goroutine使用唯一ID
			localID := "test-" + time.Now().String()
			counter := 0

			for pb.Next() {
				// 随机更换ID，模拟真实场景
				if counter%10 == 0 {
					localID = "test-" + string(rune(counter%26+'a'))
				}
				counter++

				locker.Lock(localID)
				locker.Unlock(localID)
			}
		})
	})
}

// 高争用场景测试 - 相同ID
func BenchmarkCompareHighContentionSameID(b *testing.B) {
	const sharedID = "shared-id"

	// 1. 使用我们的IDLocker
	b.Run("IDLocker", func(b *testing.B) {
		locker := NewIDLocker()
		defer locker.Close()

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				locker.Lock(sharedID)
				locker.Unlock(sharedID)
			}
		})
	})

	// 2. 使用简单的map实现
	b.Run("SimpleMapLocker", func(b *testing.B) {
		locker := NewSimpleIDLocker()

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				locker.Lock(sharedID)
				locker.Unlock(sharedID)
			}
		})
	})
}

// 测试超时锁性能
func BenchmarkLockWithTimeout(b *testing.B) {
	locker := NewIDLocker()
	defer locker.Close()

	// 准备好一些锁定状态的ID和可用的ID
	lockedIDs := make([]string, 5)
	for i := range lockedIDs {
		id := "locked-" + string(rune('a'+i))
		lockedIDs[i] = id
		locker.Lock(id)
	}

	availableIDs := make([]string, 10)
	for i := range availableIDs {
		availableIDs[i] = "available-" + string(rune('a'+i))
	}

	b.Run("AvailableID", func(b *testing.B) {
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			id := availableIDs[i%len(availableIDs)]
			if locker.LockWithTimeout(id, 100*time.Millisecond) {
				locker.Unlock(id)
			}
		}
	})

	b.Run("LockedID", func(b *testing.B) {
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			id := lockedIDs[i%len(lockedIDs)]
			// 短超时，通常会失败
			if locker.LockWithTimeout(id, 1*time.Millisecond) {
				locker.Unlock(id)
			}
		}
	})

	// 清理
	for _, id := range lockedIDs {
		locker.Unlock(id)
	}
}

// 测试大量不同ID的内存和性能影响
func BenchmarkManyDifferentIDs(b *testing.B) {
	locker := NewIDLockerWithExpiration(5 * time.Second)
	defer locker.Close()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		// 使用大量不同的ID
		id := "many-ids-test-" + string(rune(i%1000+'a')) + string(rune(i/1000+'a'))
		locker.Lock(id)
		locker.Unlock(id)

		// 每创建1000个不同的ID，等待一小段时间让清理有机会运行
		if i > 0 && i%1000 == 0 {
			time.Sleep(time.Millisecond)
		}
	}
}
